﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Forums.OfflineStore;
using System.Reflection;

namespace Microsoft.Forums.Tests.HelperTools
{
    /// <summary>
    /// Helps to create in memory forum objects
    /// </summary>
    public static class ForumObjectHelper
    {
        /// <summary>
        /// Makes a new post.
        /// </summary>
        /// <param name="subject">The subject.</param>
        /// <param name="forumId">The forum id.</param>
        /// <param name="threadId">The thread id.</param>
        /// <param name="parentId">The parent id.</param>
        /// <returns></returns>
        public static Post MakeNewPost(string subject, Guid forumId, Guid threadId, Guid? parentId)
        {
            var id = Guid.NewGuid();
            var newPost = new Post
            {
                Id = id,
                Subject = "SomeSubject",
                ParentId = parentId,
                ThreadId = threadId,
                ForumId = forumId,
                PostPropertySet = new PostPropertySet { PostId = id },
                ModifiedOn = DateTime.Now,
                CreatedOn = DateTime.Now,
                CreatedBy = MakeNewUser()
            };

            return newPost;
        }

        /// <summary>
        /// Makes a new thread.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="forumId">The forum id.</param>
        /// <returns></returns>
        public static Thread MakeNewThread(string topic, Guid forumId)
        {
            var id = Guid.NewGuid();
            var newThread = new Thread
            {
                Id = id,
                Topic = "SomeSubject",
                ForumId = forumId,
                RootPostId = Guid.NewGuid(),
                ThreadPropertySet = new ThreadPropertySet { ThreadId = id },
                CreatedOn = DateTime.Now,
                CreatedById = Guid.NewGuid(),
                ModifiedOn = DateTime.Now,
                ModifiedById = Guid.NewGuid()
            };

            return newThread;
        }

        /// <summary>
        /// Makes a new forum.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="providerId">The provider id.</param>
        /// <returns></returns>
        public static Forum MakeNewForum(string name, Guid providerId)
        {
            var id = Guid.NewGuid();
            var newForum = new Forum
            {
                Id = id,
                ForumServiceProviderId = providerId,
                Name = name,
                DisplayName = name,
                ModifiedOn = DateTime.Now,
                ForumPropertySet = new ForumPropertySet { ForumId = id }
            };

            return newForum;
        }

        /// <summary>
        /// Makes the new user.
        /// </summary>
        /// <returns></returns>
        public static User MakeNewUser()
        {
            var newUser = new User { 
                Id = Guid.NewGuid(), 
                DisplayName = "SomeName",
                LastActiveDate = DateTime.Now, 
                JoinedDate = DateTime.Now };

            return newUser;
        }

        /// <summary>
        /// Makes the pending action.
        /// </summary>
        /// <param name="status">The status.</param>
        /// <param name="type">The type.</param>
        /// <returns>A new pending action</returns>
        public static PendingAction MakePendingAction(ActionStatus status, ActionType type, Guid providerId)
        {
            var pendingAction = new PendingAction
            {
                ActionStatus = (int)status,
                ActionType = (int)type,
                ForumId = Guid.NewGuid(),
                ForumServiceProviderId = providerId
            };
            return pendingAction;


        }

        /// <summary>
        /// Create a duplicate of an object
        /// 
        /// This lets us create copies of database objects and then modify them 
        /// and use them as return values from the webservice
        /// </summary>
        /// <typeparam name="T">type we are duplicating</typeparam>
        /// <param name="sourceObject"></param>
        /// <returns></returns>
        public static T Duplicate<T>(T sourceObject) where T : new()
        {
            T destObject = new T();
            Copy(sourceObject, ref destObject);
            return destObject;
        }

        /// <summary>
        /// Copy one object to another for each matching property
        /// </summary>
        /// <typeparam name="T">Type we are copying</typeparam>
        /// <param name="sourceObject"></param>
        /// <param name="destObject"></param>
        public static void Copy<T>(T sourceObject, ref T destinationObject)
        {
            if (sourceObject == null || destinationObject == null)
                return;

            Type sourceType = sourceObject.GetType();
            Type targetType = destinationObject.GetType();

            foreach (PropertyInfo p in sourceType.GetProperties())
            {
                // only copy ceartin type
                if (p.PropertyType != typeof(string) &&
                   p.PropertyType != typeof(int) &&
                   p.PropertyType != typeof(Guid) &&
                   p.PropertyType != typeof(DateTime))
                {
                    continue;
                }
                if (!p.CanWrite || !p.CanRead) continue;

                PropertyInfo targetObj = targetType.GetProperty(p.Name);

                if (targetObj == null)
                    continue;

                targetObj.SetValue(destinationObject, p.GetValue(sourceObject, null), null);
            }
        }
    }
}
